package com.unknownman.block.transaction.subscribe;

import com.lianziyou.chain.common.config.BscWeb3jConfig;
import com.unknownman.block.component.MessageSolver;
import com.unknownman.block.component.MessageSolverChooser;
import com.unknownman.block.constants.ChainContractConstants;
import com.unknownman.block.constants.LogConstants;
import com.unknownman.block.dto.ChainContractComposition;
import com.unknownman.block.entity.TContractConfig;
import com.unknownman.block.entity.TContractLogs;
import com.unknownman.block.service.TChainConfigService;
import com.unknownman.block.service.TContractLogsService;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.cloud.utils.CollectionUtil;
import org.cloud.utils.SpringContextUtil;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.protocol.core.methods.response.Log;
import org.web3j.protocol.core.methods.response.TransactionReceipt;

@Slf4j
public class BscTranFilter2 extends BaseTranFilter {

    private MessageSolverChooser messageSolverChooser;

    private TChainConfigService chainConfigService;
    private TContractLogsService contractLogsService;
    private Web3j web3j;

    private ChainContractComposition chainContractComposition;

    private Map<String, TContractConfig> contractConfigMap;

    public BscTranFilter2(ChainContractComposition chainContractComposition) {
        super(BscWeb3jConfig.BscWeb3j.class);
        this.chainContractComposition = chainContractComposition;
        //查出启用的合约地址
        contractConfigMap = this.chainContractComposition.getContractList().stream()
            .filter(cont -> cont.getContractStatus() == ChainContractConstants.ContractStatusConstants.NORMAL.getStatus())
            .collect(Collectors.toMap((contractConfig) -> contractConfig.getContractAddress().toUpperCase(), Function.identity()));

        chainConfigService = SpringContextUtil.getBean(TChainConfigService.class);
        contractLogsService = SpringContextUtil.getBean(TContractLogsService.class);
        messageSolverChooser = SpringContextUtil.getBean(MessageSolverChooser.class);
        web3j = SpringContextUtil.getBean(BscWeb3jConfig.BscWeb3j.class);
    }

    @Override
    public void subscribeCallBack(TransactionReceipt transactionReceipt) throws Exception {
        List<Log> logs = transactionReceipt.getLogs();
        if (CollectionUtil.single().isEmpty(logs)) {
            return;
        }
        EthBlock.Block block = web3j.ethGetBlockByHash(transactionReceipt.getBlockHash(), false).send().getBlock();
        Long timestamp = block.getTimestamp().longValue() * 1000;
        ArrayList<TContractLogs> saveLogList = new ArrayList<>();
        for (Log log : logs) {
            //判断是不是监听的日志
            TContractConfig contractConfig = contractConfigMap.get(log.getAddress().toUpperCase());
            if (contractConfig == null) {
                continue;
            }
            if (!contractLogsService.existsByHashAndIndex(transactionReceipt.getTransactionHash(), log.getLogIndex().longValue())) {
                TContractLogs contractLogs = new TContractLogs();
                contractLogs.setContractConfigId(contractConfig.getContractConfigId());
                contractLogs.setContractAddress(log.getAddress());
                contractLogs.setTransFrom(transactionReceipt.getFrom());
                if (!StringUtils.isEmpty(transactionReceipt.getContractAddress())) {
                    contractLogs.setTransTo(transactionReceipt.getContractAddress());
                } else {
                    contractLogs.setTransTo(transactionReceipt.getTo());
                }
                contractLogs.setTransHash(transactionReceipt.getTransactionHash());
                contractLogs.setIndexForBlock(log.getLogIndex().longValue());
                contractLogs.setBlockTimestamp(new Date(timestamp));
                List<String> topics = log.getTopics();
                contractLogs.setFirstTopic(topics.get(0));
                if (topics.size() >= 2) {
                    contractLogs.setSecondTopic(topics.get(1));
                }
                if (topics.size() >= 3) {
                    contractLogs.setThirdTopic(topics.get(2));
                }
                if (topics.size() >= 4) {
                    contractLogs.setFourthTopic(topics.get(3));
                }
                contractLogs.setLogData(log.getData());
                contractLogs.setStatus(LogConstants.ContractLogStatus.UNTREATED.getStatus());
                saveLogList.add(contractLogs);
                //消息发送
                //根据合约分发消息
                MessageSolver messageSolver = messageSolverChooser.choose(log.getAddress().toUpperCase());
                if (messageSolver != null) {
                    messageSolver.solve(log);
                }
            }
        }
        if (CollectionUtil.single().isNotEmpty(saveLogList)) {
            boolean b = contractLogsService.saveBatch(saveLogList);
            Assert.isTrue(b, "subscribeCallBack-" + chainContractComposition.getChainSymbol() + "：log保存失败");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateLastBlock(BigInteger block, boolean success) {
        chainConfigService.updateLastBlock(chainContractComposition.getChainConfigId(), block.longValue(), success);
    }
}
